<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        body{ /*背景样式*/
            overflow: hidden;

            background: url(./imgs/02.jpg) no-repeat;
            /*引入背景图片*/

            /*background-size: cover;*/
            /*背景平铺*/
        }
        .box{ /*流星样式*/
            position:absolute;
            width:300px;
            height:4px;
            border-radius:4px;
            transform:rotate(-30deg);
            background-image: linear-gradient(to right,#fff 25%,transparent  80%,#222 100%);
        }
        .box::before,
        .box::after{ /*流星的伪元素样式*/
            position: absolute;
            content: "";
            width: inherit;
            height: inherit;
            background-image:inherit;
            filter: blur(10px);
        }
    </style>
</head>
<body>
<script>

    //抽象出一个专门生成流星的构造函数Star
    class Star{
        constructor() { //构造器

            //创建一个流星，即构造函数Star实例出一个实例对象流星star
            this.color = "#" + Math.random().toString(16).slice(2,8) //随机颜色，# + 裁切6位数
            this.star = Star.init(this.color) //静态方法不能被实例对象流星star调用，就只能用构造函数Star直接访问，将随机颜色作为参数传入
            //这里Star访问init方法就会生成并返回一个流星元素节点，我们用this.star来接收返回的这个元素，方便后续操作生成的流星

            //流星的初始位置坐标
            this.startPoint = {
                x:Math.random() * 2000, //初始x坐标
                y:Math.random() * 60 //初始y坐标
            }

            //流星的运动时间 随机 5s 到 10s
            this.duration = 5000 * Math.random() + 5000

            //流星的当前位置坐标
            this.currentPoint = {
                x:this.startPoint.x, //当前x坐标
                y:this.startPoint.y //当前y坐标
            }

            //流星的运动速率
            let sv = 0.2 * Math.random() + 0.4 //随机 0.4 到 0.6
            this.speed = { //让每次移动的x和y都相等，才不显得生硬奇怪
                vx:-sv, //x坐标向左运动取负数
                vy:sv //y坐标向下运动取正数
            }

            //先强行绑定流星不停运动渲染时this.animation的this指向
            this.animation = this.animation.bind(this) //react的this指向问题的解决方法

            //进行第一次渲染，让流星出现在它的开始位置
            this.render(this.startPoint) //render方法执行，渲染出流星
        }

        //抽象出创建流星的init方法，不想被别人调用，使用静态方法static
        static init(color){ //接收一个形参color
            let div = document.createElement("div") //createElement方法会创建并返回一个div标签元素节点，这个div标签元素节点就是流星
            div.className = "box" //div标签元素节点的类名叫box（盒子）
            div.style.backgroundColor = color //给这个div标签元素节点设置背景颜色
            document.body.appendChild(div) //将创建的div标签元素节点流星添加到页面中的body标签元素当中
            return div //将这个div标签元素节点流星返回出去，只有返回出去才能被外部访问并操作流星
        }

        //抽象出流星的渲染函数render 传入什么坐标点渲染什么坐标点
        render(point){
            this.star.style.left = point.x + "px"
            this.star.style.top = point.y + "px"
        }

        //抽象出流星开始运动
        start(){ //一旦执行start就表示运动开始

            //获取开始运动的时间
            this.startTime = new Date()

            //不停地开始渲染动画
            this.animation()
        }

        //记录时间的渲染动画函数
        animation(){

            //获取现在的时间
            let current = new Date()

            if(current - this.startTime > this.duration) { //如果现在的时间-开始运动的时间>流星运动的时间，就停止渲染动画

                //清除这个流星
                document.body.removeChild(this.star)

                return
            }

            //下面就是真正运动的描述
            requestAnimationFrame(this.animation) //requestAnimationFrame 关键帧回调 可以保证函数执行频率和页面刷新频率一致

            //就可以计算当前的位置 sx = s0 + (tx - t0) * v
            //元素这一时刻的位置 = 初始位置 + （任意时刻 - 开始运动的时刻）* 元素的运动速度
            this.currentPoint.x = this.startPoint.x + (current - this.startTime) * this.speed.vx
            this.currentPoint.y = this.startPoint.y + (current - this.startTime) * this.speed.vy

            //执行render
            this.render(this.currentPoint)
        }
    }

    //创建一个流星开始运动函数
    function starStart(){ //可以将这个函数传到定时器中执行，执行几次出现几个流星
        let star = new Star()
        return star.start()
    }

    //创建一个定时器，每隔0.5s执行一次流星运动函数
    let timer = setInterval(() => { //定时器中每次让两个流星开始运动
        starStart()
        starStart()
    },500)
</script>
</body>
</html>